﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.ProgressBar;
using YJKRevitBase.WinForm;
using YJKOpeningCommon.DataEnum;
using YJKOpeningCommon.DbOpening;
using YJKOpeningCommon.Public;
using YJKOpeningDesignInput.ConfigForm;
using YJKOpeningDesignInput.DbOpeningCreatorFactory;
using YJKOpeningDesignInput.EquipCollector;
using YJKOpeningDesignInput.Public;

namespace YJKOpeningDesignInput.Cmd
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class CmdOpeningDesignInput : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string messages, ElementSet elements)
		{
			if (cmdData.Application.ActiveUIDocument.Document.IsModified)
			{
				MessageBox.Show("请先保存项目。", "盈建科提示");
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			OpeningSelectForm openingSelectForm = new OpeningSelectForm();
			openingSelectForm.ShowDialog();
			if (openingSelectForm.DialogResult == DialogResult.OK)
			{
				ESelectModel eSelectModel;
				if (openingSelectForm.IsSelectLevel)
				{
					eSelectModel = ESelectModel.eLevel;
				}
				else if (openingSelectForm.IsSelectBox)
				{
					eSelectModel = ESelectModel.ePickBox;
				}
				else
				{
					eSelectModel = ESelectModel.eProject;
				}
				if (!(cmdData.Application.ActiveUIDocument.Document.ActiveView is ViewPlan))
				{
					MessageBox.Show("请切换到平面视图运行此命令！", "盈建科提示");
					return Autodesk.Revit.UI.Result.Cancelled;
				}
				MEPData mepdata = new MEPData();
				LinkedList<DbOpeningBase> lstDbOpening = new LinkedList<DbOpeningBase>();
				UIDocument activeUIDocument = cmdData.Application.ActiveUIDocument;
				Document document = activeUIDocument.Document;
				List<Document> list = new List<Document>();
				list.Add(document);
				IEnumerable<Document> enumerable = CommonInterface.GetLinkDocs(document).Distinct<Document>();
				if (enumerable != null && enumerable.Count<Document>() != 0)
				{
					list.AddRange(enumerable);
				}
				if (!this.GetAllMEPCurve(list, ref mepdata, openingSelectForm, cmdData))
				{
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				new EquipMentCollector(document).GetEquips(ref mepdata, openingSelectForm, cmdData, this.m_PickedBox);
				new List<Grid>();
				if (!GridData.GetGridInfos(list, ref mepdata.m_lstInfos))
				{
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
                this._hWndRevit = new WindowHandle(mainWindowHandle);
				if (!this.GetAllOpeningData(list, ref lstDbOpening, mepdata))
				{
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				GraphicsStyle graphicsStyle = null;
				CommonInterface.GetPreViewStyle(ref graphicsStyle, document);
				if (graphicsStyle == null)
				{
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				PreViewScene preViewScene = new PreViewScene(document, graphicsStyle.Id, 0.32808398950131235);
				Autodesk.Revit.DB.View activeView = document.ActiveView;
				using (TransactionGroup transactionGroup = new TransactionGroup(document))
				{
					try
					{
						transactionGroup.Start("TransGroupCreateModelGroup");
						if (!this.CreatePreviewIns(ref lstDbOpening, document, preViewScene))
						{
							return Autodesk.Revit.UI.Result.Succeeded;
						}
						this.OpeningDesignInputFormShow(lstDbOpening, cmdData, eSelectModel);
					}
					catch (Exception ex)
					{
                        if ((int)transactionGroup.GetStatus() == 1)
						{
							transactionGroup.RollBack();
						}
						if (document.ActiveView.Id != activeView.Id && activeView.Name.CompareTo("项目视图") != 0)
						{
							activeUIDocument.ActiveView = activeView;
						}
						ExceptionLog.WriteLog(ex.Message, true);
						throw;
					}
					finally
					{
						if (transactionGroup.HasStarted())
						{
							transactionGroup.RollBack();
						}
						if (document.ActiveView.Id != activeView.Id && activeView.Name.CompareTo("项目视图") != 0)
						{
							activeUIDocument.ActiveView = activeView;
						}
						ExceptionLog.CloseLogFile();
					}
				}
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool CreatePreviewIns(ref LinkedList<DbOpeningBase> lstDbOpening, Autodesk.Revit.DB.Document doc, PreViewScene preViewScene)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstDbOpening.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "创建洞口预览";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this._hWndRevit);
				foreach (DbOpeningBase dbOpeningBase in lstDbOpening)
				{
					Element element = null;
					dbOpeningBase.CreateOpeningPreviewInstance(out element, preViewScene);
					if (element != null)
					{
						dbOpeningBase.m_idModelGroup = element.Id;
					}
					progressBarForm.RefreshProgressBar();
					if (progressBarForm.m_stopTag)
					{
						return false;
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception)
			{
				progressBarForm.Dispose();
				throw;
			}
			return result;
		}

		private void OpeningDesignInputFormShow(LinkedList<DbOpeningBase> lstDbOpening, ExternalCommandData cmdData, ESelectModel eSelectModel)
		{
			UIDocument activeUIDocument = cmdData.Application.ActiveUIDocument;
			Document document = activeUIDocument.Document;
			CommonInterface.SetView3DChanged(activeUIDocument);
			OpeningDesignInputReportForm openingDesignInputReportForm = new OpeningDesignInputReportForm(lstDbOpening, cmdData, this._hWndRevit, eSelectModel);
			openingDesignInputReportForm.SetOpeningData2DataGridView();
			openingDesignInputReportForm.Show(this._hWndRevit);
			int wMsg = 7;
			CmdOpeningDesignInput.SendMessage(this._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Selection selection = activeUIDocument.Selection;
			for (;;)
			{
				try
				{
					selection.PickElementsByRectangle("");
					List<Element> selElements = new List<Element>();
					RevitVersionFuncs.SetSelection(activeUIDocument.Selection, selElements);
					activeUIDocument.RefreshActiveView();
					continue;
				}
				catch (Exception)
				{
				}
				break;
			}
			openingDesignInputReportForm.Close();
		}

		private bool GetAllOpeningData(List<Document> lstDoc, ref LinkedList<DbOpeningBase> lstDbOpening, MEPData m_mepData)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Interface.GetXmlData(ref dictionary);
			bool result;
			try
			{
				if (!new DbWallStraightOpeningCreateFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbFloorOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbBeamOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbEquipWallOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else
				{
					result = true;
				}
			}
			catch (Exception ex)
			{
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		private FilteredElementCollector SelectMode(OpeningSelectForm openingSelectForm, ExternalCommandData cmdData, Autodesk.Revit.DB.Document doc, FilteredElementCollector collector, double height)
		{
			if (openingSelectForm.IsSelectBox)
			{
				if (this.m_PickedBox == null)
				{
					this.m_PickedBox = cmdData.Application.ActiveUIDocument.Selection.PickBox((Autodesk.Revit.UI.Selection.PickBoxStyle)0, "选择范围");
				}
				BoundingBoxXYZ boundingBoxXYZ = new BoundingBoxXYZ();
				boundingBoxXYZ.Max = this.m_PickedBox.Max;
				boundingBoxXYZ.Min = this.m_PickedBox.Min;
				double num = 0.0;
				double num2 = 0.0;
				double num3 = 0.0;
				double num4 = 0.0;
				this.CheckMaxXY(boundingBoxXYZ, ref num, ref num2, ref num3, ref num4);
				boundingBoxXYZ.Max = new XYZ(num, num2, 0.0);
				boundingBoxXYZ.Min = new XYZ(num3, num4, 0.0);
				collector = SolidFilter.GetIntersectsSolid(cmdData.Application.ActiveUIDocument.Document, SolidFilter.CreateSolid(cmdData.Application.ActiveUIDocument.Document, boundingBoxXYZ, height, cmdData.Application.ActiveUIDocument.Document.ActiveView.GenLevel.Elevation), collector);
			}
			if (openingSelectForm.IsSelectLevel)
			{
				BoundingBoxXYZ cropBox = cmdData.Application.ActiveUIDocument.Document.ActiveView.CropBox;
				double num5 = 1000000.0;
				double num6 = 1000000.0;
				double num7 = -1000000.0;
				double num8 = -1000000.0;
				cropBox.Max = new XYZ(num5, num6, 0.0);
				cropBox.Min = new XYZ(num7, num8, 0.0);
				collector = SolidFilter.GetIntersectsSolid(cmdData.Application.ActiveUIDocument.Document, SolidFilter.CreateSolid(cmdData.Application.ActiveUIDocument.Document, cropBox, height, cmdData.Application.ActiveUIDocument.Document.ActiveView.GenLevel.Elevation), collector);
			}
			return collector;
		}

		private void CheckMaxXY(BoundingBoxXYZ boundingBoxXYZref, ref double maxX, ref double maxY, ref double minX, ref double minY)
		{
			if (boundingBoxXYZref.Max.X > boundingBoxXYZref.Min.X)
			{
				maxX = boundingBoxXYZref.Max.X;
				minX = boundingBoxXYZref.Min.X;
			}
			else
			{
				minX = boundingBoxXYZref.Max.X;
				maxX = boundingBoxXYZref.Min.X;
			}
			if (boundingBoxXYZref.Max.Y > boundingBoxXYZref.Min.Y)
			{
				maxY = boundingBoxXYZref.Max.Y;
				minY = boundingBoxXYZref.Min.Y;
				return;
			}
			minY = boundingBoxXYZref.Max.Y;
			maxY = boundingBoxXYZref.Min.Y;
		}

		private bool GetAllMEPCurve(List<Document> lstDoc, ref MEPData mepData, OpeningSelectForm openingSelectForm, ExternalCommandData cmdData)
		{
			bool result;
			try
			{
				List<double> level = Common.GetLevel(cmdData.Application.ActiveUIDocument.Document);
				int num = level.IndexOf(cmdData.Application.ActiveUIDocument.Document.ActiveView.GenLevel.Elevation);
				double height = 0.0;
				if (num < level.Count - 1)
				{
					height = level[num + 1] - level[num];
				}
				else
				{
					height = 13.0;
				}
				foreach (Autodesk.Revit.DB.Document document in lstDoc)
				{
					FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document);
					filteredElementCollector.OfCategory(BuiltInCategory.OST_DuctCurves).WhereElementIsNotElementType();
					filteredElementCollector = this.SelectMode(openingSelectForm, cmdData, document, filteredElementCollector, height);
					foreach (Element element in filteredElementCollector)
					{
						Duct duct = element as Duct;
						foreach (object obj in duct.ConnectorManager.Connectors)
						{
							Connector connector = (Connector)obj;
                            if ((int)connector.ConnectorType == 1 && ((int)connector.Shape == 1 || connector.Shape == null))
							{
								mepData.m_lstDuct.Add(duct);
								break;
							}
						}
					}
				}
				foreach (Autodesk.Revit.DB.Document document2 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector2 = new FilteredElementCollector(document2);
					filteredElementCollector2.OfCategory(BuiltInCategory.OST_CableTray).WhereElementIsNotElementType();
					filteredElementCollector2 = this.SelectMode(openingSelectForm, cmdData, document2, filteredElementCollector2, height);
					foreach (Element element2 in filteredElementCollector2)
					{
						mepData.m_lstCableTray.Add(element2 as CableTray);
					}
				}
				foreach (Autodesk.Revit.DB.Document document3 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector3 = new FilteredElementCollector(document3);
					filteredElementCollector3.OfCategory(BuiltInCategory.OST_PipeCurves).WhereElementIsNotElementType();
					filteredElementCollector3 = this.SelectMode(openingSelectForm, cmdData, document3, filteredElementCollector3, height);
					foreach (Element element3 in filteredElementCollector3)
					{
						mepData.m_lstPipe.Add(element3 as Pipe);
					}
				}
				foreach (Autodesk.Revit.DB.Document document4 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector4 = new FilteredElementCollector(document4);
					filteredElementCollector4.OfCategory(BuiltInCategory.OST_GenericModel).WhereElementIsNotElementType();
					filteredElementCollector4 = this.SelectMode(openingSelectForm, cmdData, document4, filteredElementCollector4, height);
					foreach (Element element4 in filteredElementCollector4)
					{
						FamilyInstance item = element4 as FamilyInstance;
						mepData.m_lstMass.Add(item);
					}
				}
				result = true;
			}
			catch (Exception ex)
			{
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		private PickedBox m_PickedBox;

        public WindowHandle _hWndRevit;
	}
}
